using Rogan.Utility.Common;
using Rogan.Utility.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Rogan.Data
{
	[Serializable]
	public class EntityQueryExpression : IDbExpression
	{
		private bool? _isOrderBy;
		public DbExpressionType ExpressionType
		{
			get
			{
				return DbExpressionType.EntityQuery;
			}
		}
		public SelectExpression Select
		{
			get;
			set;
		}
		public WhereExpression Where
		{
			get;
			set;
		}
		public IList<JoinExpression> Joins
		{
			get;
			set;
		}
		public IList<OrderByExpression> OrderByList
		{
			get;
			set;
		}
		public GroupByExpression GroupBy
		{
			get;
			set;
		}
		public Entity From
		{
			get;
			set;
		}
		public List<Entity> JoinEntities
		{
			get;
			set;
		}
		public bool? IsDistinct
		{
			get;
			set;
		}
		public int? StartIndex
		{
			get;
			set;
		}
		public int? EndIndex
		{
			get;
			set;
		}
		public bool IsPagable
		{
			get
			{
				return IsSkip && IsTop;
			}
		}
		public bool IsSkip
		{
			get
			{
				return StartIndex.HasValue && StartIndex.Value != 0;
			}
		}
		public bool IsTop
		{
			get
			{
				return EndIndex.HasValue && EndIndex.Value != 0;
			}
		}
		public bool IsIdentityFieldDesc
		{
			get
			{
				if (OrderByList == null || OrderByList.Count == 0)
				{
					return false;
				}
				if (OrderByList.Any(c => c.Field.Equals(From.GetIdentityField())))
				{
					OrderByExpression orderByExpression = OrderByList.First(c => c.Field.Equals(From.GetIdentityField()));
					return orderByExpression.Direction == OrderByDirection.Desc;
				}
				return false;
			}
		}
		public bool IsOrderBy
		{
			get
			{
				if (_isOrderBy.HasValue)
				{
					return _isOrderBy.Value;
				}
				return OrderByList != null && OrderByList.Count != 0;
			}
			set
			{
				_isOrderBy = value;
			}
		}
		public List<Field> SelectFields
		{
			get
			{
				List<Field> fields = Select.Fields;
				if (IsShowAllField(From.GetName()))
				{
					fields.AddRange(From.GetFields().ToList());
				}
				List<Entity> joinEntities = JoinEntities;
				if (joinEntities != null)
				{
					foreach (Entity current in joinEntities)
					{
						if (IsShowAllField(current.GetName()))
						{
							fields.AddRange(current.GetFields().ToList());
						}
					}
				}
				return fields;
			}
		}
		public bool IsShowAllField()
		{
			if (Select == null)
			{
				return true;
			}
			if (Select.Fields == null || Select.Fields.Count == 0)
			{
				return true;
			}
			List<Field> fields = Select.Fields;
			return fields.Any(c => c.FieldName.Contains("*"));
		}
		public bool IsShowAllField(string tableName)
		{
			if (Select == null)
			{
				return true;
			}
			if (Select.Fields == null || Select.Fields.Count == 0)
			{
				return true;
			}
			//tableName.Replace("{0}", "").Replace("{1}", "");
			List<Field> fields = Select.Fields;
			return fields.Any(c => !c.TableName.IsNullOrEmpty() && c.TableName.Replace("{0}", "").Replace("{1}", "").Equals(tableName, StringComparison.OrdinalIgnoreCase) && c.FieldName.Contains("*"));
		}
		public EntityQueryExpression(Entity from)
		{
			From = from;
			Select = new SelectExpression();
			Joins = new List<JoinExpression>();
			OrderByList = new List<OrderByExpression>();
		}
		public void AddSelect(Field[] fields)
		{
			AddSelect(new SelectExpression(fields));
		}
		public void AddSelect(SelectExpression expression)
		{
			foreach (Field current in expression.Fields)
			{
				Select.Fields.Add(current);
			}
		}
		public void AddWhere(WhereExpression expression)
		{
			if (expression == null)
			{
				return;
			}
			if (Where == null)
			{
				Where = expression;
				return;
			}
			Where = WhereExpression.Create(Where, expression, QueryOperator.And);
		}
		public void AddJoin(Entity entity, JoinExpression joinExp)
		{
			Guard.IsNotNull(joinExp, "JoinExpression");

			if (JoinEntities == null)
			{
				JoinEntities = new List<Entity>();
			}
			if (Joins == null)
			{
				Joins = new List<JoinExpression>();
			}
			JoinEntities.Add(entity);
			Joins.Add(joinExp);
		}
		public void AddOrderBy(OrderByExpression[] orderbys)
		{
			Guard.IsNotNull(orderbys, "OrderByExpression");
			for (int i = 0; i < orderbys.Length; i++)
			{
				OrderByExpression orderby = orderbys[i];
				AddOrderBy(orderby);
			}
		}
		public void AddOrderBy(OrderByExpression orderby)
		{
			Guard.IsNotNull(orderby, "OrderByExpression");
			if (OrderByList == null)
			{
				OrderByList = new List<OrderByExpression>();
			}
			OrderByList.Add(orderby);
		}
		public void AddGroupBy(Field[] fields)
		{
			if (GroupBy == null)
			{
				GroupBy = new GroupByExpression();
			}
			for (int i = 0; i < fields.Length; i++)
			{
				Field item = fields[i];
				GroupBy.Fields.Add(item);
			}
		}
		public void AddGroupBy(GroupByExpression expression)
		{
			if (GroupBy == null)
			{
				GroupBy = new GroupByExpression();
			}
			foreach (Field current in expression.Fields)
			{
				GroupBy.Fields.Add(current);
			}
		}
		public void AddGroupByHaving(WhereExpression expression)
		{
			if (GroupBy == null)
			{
				GroupBy = new GroupByExpression();
			}
			GroupBy.Having = expression;
		}
		public EntityQueryExpression Clone()
		{
			return DataHelper.Clone(this) as EntityQueryExpression;
		}
	}
}
